﻿String.prototype.trim = function () {
    return this.replace(/^\s*/, "").replace(/\s*$/, "");
}


function StructuredEditor(config) {
    this.content = $(config.container).html().trim();

    this.config = config;
    this.undoBuffer = new Array();
    this.headers = true;
    
    this.refresh();
}

StructuredEditor.prototype.toggleHeaders = function () {
    this.headers = !this.headers;
    this.refresh();
}

StructuredEditor.prototype.getContent = function () {
    this.saveContent(false);
    return $(this.content).html();
}
StructuredEditor.prototype.viewSource = function () {
    this.saveContent(false);
}

StructuredEditor.prototype.setContent = function (content) {
    if (content == null || content == "")
        content = "<content></content>";

    this.content = content;
    this.refresh();
}

StructuredEditor.prototype.isAllowedContent = function (tag) {
    switch (tag.toLowerCase()) {
        case "p":
        case "h1":
        case "h2":
        case "h3":
        case "h4":
        case "h5":
        case "h6":
        case "div":
        case "ul":
        case "ol":
            return true;
            break;
        default:
            return false;
            break;
    }
}

StructuredEditor.prototype.refresh = function (focusIndex) {


    var me = this;
    var html = ""

    if (me.config.defaultElement == null) {
        //  assume p
        me.config.defaultElement = { name: 'Paragraph', element: 'p' };
    }

    if ($(this.content).children().length == 0) {
        html = "<p><i>No Content has been defined for this property. <a href='#' class='insertParagraph'>Insert " + me.config.defaultElement.name + "</i></p>";
        $(this.config.container).html(html);

        $(this.config.container).find("a").click(function () {
            me.setContent("<content><" + me.config.defaultElement.element + "></" + me.config.defaultElement.element + "></content>");
            $(me.config.container).children(".ui-editor-block-editor").focus();
        });
    }
    else {

        $(this.content).children().each(function (i, c) {
            var blockName = "";
            var blackTag = "";
            switch (c.tagName.toLowerCase()) {
                case "p":
                    blockName = "paragraph";
                    blockTag = "p";
                    break;
                case "h1":
                    blockName = "heading 1";
                    blockTag = "h1";
                    break;
                case "h2":
                    blockName = "heading 2";
                    blockTag = "h2";
                    break;
                case "h3":
                    blockName = "heading 3";
                    blockTag = "h3";
                    break;
                case "h4":
                    blockName = "heading 4";
                    blockTag = "h4";
                    break;
                case "h5":
                    blockName = "heading 5";
                    blockTag = "h5";
                    break;
                case "h6":
                    blockName = "heading 6";
                    blockTag = "h6";
                    break;
                case "div":
                    blockName = "div";
                    blockTag = "div";
                    break;
            }

            if (blockName != "") {
                //html += "<div class=\"ui-editor-block\">"
                var className = $(c).attr("class");
                if (className == "" || className == null)
                    className = "none";

                if (me.headers) {
                    html += "<span index=\"" + i + "\"  class=\"ui-editor-block-header ui-editor-blocktag\">" + blockName + " - &lt;" + blockTag + "&gt;</span>";
                    html += "<span class=\"ui-editor-block-header\">style - " + className + "</span>";

                    html += "&nbsp;";
                    html += "<img class=\"ui-editor-insertblock\" index=\"" + i + "\" style=\"vertical-align:middle\" title=\"insert block\" src=\"" + resolveUrl("~/Images/Icons/add.png") + "\"/>";
                    html += "<img class=\"ui-editor-deleteblock\" index=\"" + i + "\" style=\"vertical-align:middle\" title=\"delete block\" src=\"" + resolveUrl("~/Images/Icons/delete.png") + "\"/>";
                }

                html += "<" + blockTag + " id=\"" + me.config.id + "_editorblock_" + i + "\" index=\"" + i + "\" contenteditable=\"true\" class=\"ui-editor-block-editor\">" + $(c).html() + "</" + blockTag + ">";
                //html += "</div>";
            }
            else {
                if (c.tagName.toLowerCase() == "ul" || c.tagName.toLowerCase() == "ol") {
                    switch (c.tagName.toLowerCase()) {
                        case "ul":
                            blockName = "unordered list";
                            blockTag = "ul";
                            break;
                        case "ol":
                            blockName = "ordered list";
                            blockTag = "ol";
                            break;
                    }
                    //  ok, its a list, so what we do is create
                    //  a special block for it
                    var className = $(c).attr("class");
                    if (className == "" || className == null)
                        className = "none";

                    if (me.headers) {
                        html += "<span index=\"" + i + "\"  class=\"ui-editor-block-header ui-editor-blocktag\">" + blockName + " - &lt;" + blockTag + "&gt;</span>";
                        html += "<span class=\"ui-editor-block-header\">style - " + className + "</span>";

                        html += "&nbsp;";
                        html += "<img class=\"ui-editor-insertblock\" index=\"" + i + "\" style=\"vertical-align:middle\" title=\"insert block\" src=\"" + resolveUrl("~/Images/Icons/add.png") + "\"/>";
                        html += "<img class=\"ui-editor-deleteblock\" index=\"" + i + "\" style=\"vertical-align:middle\" title=\"delete block\" src=\"" + resolveUrl("~/Images/Icons/delete.png") + "\"/>";
                    }



                    html += "<" + blockTag + " id=\"" + me.config.id + "_editorblock_" + i + "\" class=\"ui-editor-block-list\">";
                    if ($(c).children().length == 0)
                        html += "<li contenteditable=\"true\" class=\"ui-editor-block-editor\"></li>";
                    else {
                        $(c).children().each(function (i, item) {
                            html += "<li contenteditable=\"true\" class=\"ui-editor-block-editor\">" + $(item).html() + "</li>";
                        });
                    }
                    html += "</" + blockTag + ">";
                    //}
                }
            }
        });

        html += "<img class=\"ui-editor-insertblock\" index=\"-1\" style=\"vertical-align:middle\" title=\"insert block\" src=\"" + resolveUrl("~/Images/Icons/add.png") + "\"/>";

        /*
        html = "<span class=\"ui-editor-block-header\">paragraph - &lt;p&gt;</span>";
            
        html += "<span class=\"ui-editor-block-header\">insert block</span>";
        html += "<div contenteditable=\"true\" class=\"ui-editor-block\">eeee</div>";
        html += "<span class=\"ui7-editor-block-header\">insert block</span>";*/

        $(this.config.container).html(html);

        if (focusIndex != null) {
            if (focusIndex == -1)
                focusIndex = $(this.config.container).children().length - 1;

            $("#" + me.config.id + "_editorblock_" + focusIndex).focus();
        }

        $(me.config.container).find(".ui-editor-block-editor").each(function () {
            this.editor = me;
        });


        $(this.config.container).children(".ui-editor-blocktag").click(function (e) {
            me.currentIndex = parseInt($(this).attr("index"));

            $("#" + me.config.id + "_blockTag").css("left", e.pageX);
            $("#" + me.config.id + "_blockTag").css("top", e.pageY);
            $("#" + me.config.id + "_blockTag").show();
            $(document).click(function () {
                $("#" + me.config.id + "_blockTag").hide();
                e.stopPropagation();
                e.preventDefault();
            });
            e.stopPropagation();
            e.preventDefault();
        });

        //
        //  disable new lines for anything other than div
        //  we do this becuase mozilla screws up somewhat 
        //  for anything else other than divs
        $(this.config.container).find(".ui-editor-block-editor").each(function (i, c) {
            //  ok, no new lines are allowed in here                    
            $(c).keypress(function (e) {
                /*
                this needs perfecting so we
                shall leave this functionality out for now
                */
                if (e.shiftKey == true && e.which == 13) {
                    //var start = window.getSelection().anchorOffset;
                    //var content = me.getAndRemoveContentFromBlock(i, start);

                    //  shift+enter we want a new block
                    //  we copy the content over!
                    me.insertBlock(i + 1, "");
                }

                if (e.which == 8) {
                    //  are we at the start of the container, we
                    //  dont want the content to end up on the above container
                    if (me.getSelectionLength() == 0)
                        return (me.getCursorPosition() != 0);
                }

                if (e.keyCode == 46) {
                    //  ok, a backspace
                    if (me.getSelectionLength() == 0)
                        return me.getCursorPosition() != ($(c).text().length);
                }

                //  only allow the return to happen for a div
                if (e.which == 13 && c.tagName.toLowerCase() != "div") {
                    if (c.tagName.toLowerCase() == "li") {
                        //  we actually want to insert another li
                        me.insertListItem(i);
                        me.refresh();
                    }
                    return (e.which != 13);
                }

            });
        });

        $(this.config.container).children(".ui-editor-block-list").children("li").each(function (i, c) {
            $(c).keypress(function (e) {
                if (e.which == 8 || e.keyCode == 46) {
                    //
                    //  ok, we pressed delete or backspace on a block
                    if ($(c).text() == "") {
                        //  firstly save the content
                        me.saveContent(true);
                        me.refresh();

                    }
                }
            });
        });

        if (this.config.focus != null) {
            $(this.config.container).find(".ui-editor-block-editor").focus(this.config.focus);
        }


        $(this.config.container).children(".ui-editor-deleteblock").click(function () {
            me.saveContent(true);

            var index = $(this).attr("index");
            var html = "";
            $(me.content).children().each(function (i, c) {
                if (i != index) {
                    var className = $(c).attr("class");
                    var classText = "";
                    if (className != "" && className != null)
                        classText = " class=\"" + className + "\"";
                    html += "<" + c.tagName.toLowerCase() + classText + ">" + $(c).html() + "</" + c.tagName.toLowerCase() + ">";
                }
            });

            me.content = "<content>" + me.formatHtml(html) + "</content>";

            me.refresh();
        });

        $(this.config.container).children(".ui-editor-insertblock").click(function () {
            var index = $(this).attr("index");
            me.insertBlock(index);
        });
    }

    if (this.config.resize != null)
        this.config.resize();
}


StructuredEditor.prototype.getSelectionLength = function () {
    if (window.getSelection()) {
        var sel = window.getSelection();
        return Math.abs(sel.anchorOffset - sel.focusOffset);
    }

    alert("not implemented on this browser");
}

StructuredEditor.prototype.getCursorPosition = function () {
    if (window.getSelection) {
        var sel = window.getSelection();

        if (sel.anchorOffset < sel.focusOffset)
            return sel.anchorOffset;
        else
            return sel.focusOffset;
    }

    alert("not implemented on this browser");
}

StructuredEditor.prototype.formatHtml = function (html) {
    if (html == null)
        html = "";
    return html.replace("<br>", "<br/>").replace("<BR>", "<br/>");
}

StructuredEditor.prototype.getAndRemoveContentFromBlock = function (index, start) {
    var me = this;
    var ret = "";
    me.saveContent(false);
    var html = "";
    $(me.content).children().each(function (i, c) {
        var className = $(c).attr("class");
        var classText = "";
        if (className != "" && className != null)
            classText = " class=\"" + className + "\"";

        content = $(c).html();
        if (i == index) {
            ret = content.substring(start, content.length);
            content = content.substr(0, start);
        }


        html += "<" + c.tagName.toLowerCase() + classText + ">" + content + "</" + c.tagName.toLowerCase() + ">";
    });

    this.content = "<content>" + html + "</content>";
    this.refresh();
    return ret;
}


StructuredEditor.prototype.changeBlockTag = function (index, tag) {
    var me = this;
    me.saveContent(true);
    var html = "";
    $(me.content).children().each(function (i, c) {
        var className = $(c).attr("class");
        var classText = "";
        if (className != "" && className != null)
            classText = " class=\"" + className + "\"";
        var tagName = c.tagName.toLowerCase();
        var addHtml = true;

        content = $(c).html();
        if (i == index) {
            //  changing to a list from a block element
            if (tagName != "ul" && tagName != "ol") {
                tagName = tag.toLowerCase();
                if (tagName == "ul" || tagName == "ol") {
                    //  changing to a list of ol from not a list
                    //  so we take the html of the inner element and create a list
                    content = "<li>" + content + "</li>";
                }
            }
            else {
                //  we are changing from a list
                //  if we are changing to a block element, then we must 
                //  do the opposite of this
                tagName = tag.toLowerCase();
                if (tagName != "ul" && tagName != "ol") {
                    //  ok, we are changing to a list
                    //  we need to go through each item and 
                    //  create that many version of the tag
                    //  for each list element
                    $(content).children().each(function (i, item) {
                        addHtml = false;
                        html += "<" + tagName + ">" + $(item).html() + "</" + tagName + ">";
                    });
                }
            }
        }

        if (addHtml)
            html += "<" + tagName + ">" + content + "</" + tagName + ">";
    });

    this.content = "<content>" + html + "</content>";
    this.refresh();
}


StructuredEditor.prototype.insertListItem = function (index) {
    var me = this;

    me.saveContent(true);


    //
    //  build the new html string
    var html = "";
    var j = 0;
    $(me.content).children().each(function (i, c) {
        var tag = c.tagName.toLowerCase();
        var className = $(c).attr("class");
        var classText = "";
        if (className != "" && className != null)
            classText = " class=\"" + className + "\"";
        //  append the item here
        html += "<" + c.tagName.toLowerCase() + classText + ">" + $(c).html();

        //  if this is the correct item
        if (j <= index) {
            var k = j + $(c).children("li").length;

            if (k >= index) {
                //  this is where we want the list
                if (k == j) {
                    //  insert two
                    html += "<li></li><li></li>";
                }
                else
                    html += "<li></li>";
            }
            j = k;

        }

        html += "</" + c.tagName.toLowerCase() + ">";
        if(c.tagName.toLowerCase() != "ul" && c.tagName.toLowerCase() != "ol")
            j++;
    });





    me.content = "<content>" + html + "</content>";

    me.refresh(index);
}

StructuredEditor.prototype.insertBlock = function (index, content) {
    var me = this;

    me.saveContent(true);

    var blockTag = "";
    if (me.config.getNewBlockTag != null)
        blockTag = me.config.getNewBlockTag();

    if (blockTag == null || blockTag == "")
        blockTag = "p";

    if (content == null)
        content = "";

    //
    //  build the new html string
    var html = "";
    $(me.content).children().each(function (i, c) {
        if (i == index) {
            html += "<" + blockTag + ">" + content + "</" + blockTag + ">";
        }
        var className = $(c).attr("class");
        var classText = "";
        if (className != "" && className != null)
            classText = " class=\"" + className + "\"";
        html += "<" + c.tagName.toLowerCase() + classText + ">" + $(c).html() + "</" + c.tagName.toLowerCase() + ">";
    });

    //  put it on the end?
    if (index == -1 || index >= $(me.content).children().length) {
        html += "<" + blockTag + ">" + content + "</" + blockTag + ">";
    }

    me.content = "<content>" + html + "</content>";

    me.refresh(index);
}

StructuredEditor.prototype.saveContent = function (addToUndoBuffer) {
    var me = this;
    var html = "";
    $(me.content).children().each(function (i, c) {
        var className = $(c).attr("class");
        var classText = "";
        if (className != "" && className != null)
            classText = " class=\"" + className + "\"";

        switch (c.tagName.toLowerCase()) {
            case "ul":
            case "ol":
                //
                //  ok, this is a special case! ;) we are editing a list
                var content = "";
                $("#" + me.config.id + "_editorblock_" + i.toString()).children().each(function (j, item) {
                    var newHtml = me.formatHtml($(item).html());
                    //  only add the li in if it has content
                    if (newHtml != "")
                        content += "<li>" + me.formatHtml($(item).html()) + "</li>";
                });
                html += "<" + c.tagName.toLowerCase() + classText + ">" + content + "</" + c.tagName.toLowerCase() + ">";
                break;
            default:
                if(me.isAllowedContent(c.tagName))
                    html += "<" + c.tagName.toLowerCase() + classText + ">" + me.formatHtml($("#" + me.config.id + "_editorblock_" + i.toString()).html()) + "</" + c.tagName.toLowerCase() + ">";
                break;
        }
    });

    this.content = "<content>" + html + "</content>";

    if (addToUndoBuffer == true)
        this.undoBuffer.push(this.content);

}

StructuredEditor.prototype.undo = function () {
    if (this.undoBuffer.length > 0) {
        this.content = this.undoBuffer.pop();
        this.refresh();
    }
}